#include "properties.h"
#include "common.h"
#include <codecvt>
#include <fstream>
#include <locale>

bool loaded = false;

Properties::Properties(void) : common(Common::getInstance()) { loaded = false; }

Properties::~Properties(void) {}

Properties &Properties::getInstance() {
    static Properties instance;
    instance.load();
    return instance;
}

bool Properties::expandPath(String &value) {
    if (value.empty()) {
        return false;
    }

    if (value.find("/") == 0) { // 绝对路径
        return true;
    }

    if (value.find("${EXE_DIR}") == 0) {
        value = common.getExeDir() + value.substr(10);
    } else if (value.find("${JAVA_HOME}") == 0) {
        value = common.getEnvVar("JAVA_HOME") + value.substr(12);
    } else {
        value = common.getExeDir() + "/" + value;
    }
    return true;
}

void Properties::load() {
    if (loaded) {
        return;
    }

    String filename = common.getExeDir() + "/jstart.properties";
    common.debug("check file: " + filename);
    if (!common.isFileExists(filename)) {
        loaded = true;
        return;
    }

    // 读取配置文件
    common.debug("open file: " + filename);
    std::ifstream stream(filename.data());
    const std::locale emptyLocale = std::locale::classic();
    if (stream.is_open()) {
        common.debug("file: " + filename + " was opened.");
        String key;
        while (!stream.eof()) {
            std::string line;
            std::getline(stream, line);
            if (line.empty() || line[0] == L'#') { // 跳过空行和注释行
                continue;
            }
            size_t eq = line.find('=');
            if (eq == line.npos) {
                throw std::runtime_error("Invalid config item: \n" + std::string(line.begin(), line.end()));
            }
            key = line.substr(0, eq);
            String val = line.substr(eq + 1);
            std::list<String> values;
            if (line.find("exe.mainClass") == 0) {
                val = common.trimString(val);
                if (!val.empty()) {
                    map[key] = {val};
                }
            } else if (line.find("exe.mainArgs") == 0) {
                for (String value : common.splitString(common.trimString(val), ' ')) {
                    if (!value.empty()) {
                        values.push_back(value);
                    }
                }
                if (!values.empty()) {
                    map[key] = values;
                }
            } else if (line.find("exe.javaHome") == 0 || line.find("exe.classPath") == 0) {
                for (String value : common.splitString(common.trimString(val), ';')) {
                    if (expandPath(value)) {
                        values.push_back(value);
                    }
                }
                if (!values.empty()) {
                    map[key] = values;
                }
            } else if (line.find("exe.") == 0) {
                for (String value : common.splitString(common.trimString(val), ';')) {
                    values.push_back(value);
                }
                if (!values.empty()) {
                    map[key] = values;
                }
            } else {
                break;
            }
        }
    }
    loaded = true;
}

std::list<String> Properties::getJavaHome() {
    if (map.count("exe.mainClass") == 1) {
        return map["exe.javaHome"];
    }
    std::list<String> javaHome = {common.getExeDir() + "/jre", common.getEnvVar("JAVA_HOME")};
    return javaHome;
}

std::list<String> Properties::getVmOptions() { return map["exe.vmOptions"]; }

String Properties::getClassPath() {
    String fullClassPath;
    for (String path : map["exe.classPath"]) {
        fullClassPath = path + ":";
    }
    return fullClassPath.empty() ? common.getExeDir() + "/jstart.jar:" + common.getExePath() : fullClassPath;
}

String Properties::getMainClass() {
    if (map.count("exe.mainClass") == 1) {
        return map["exe.mainClass"].front();
    }
    return "jstart/exe/Main";
}

std::list<String> Properties::getMainArgs() {
    std::list<String> args = common.getCommandLineArgs();
    return args.empty() ? map["exe.mainArgs"] : args;
}